package com.nanyang.tms.controller.interceptor;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.nanyang.common.core.annotation.BindParam;
import com.nanyang.common.core.dict.CommonEnum;
import com.nanyang.common.core.exception.ServiceException;


/**
 * @ClassName: ParamAspect
 * @Description: TODO( aop 切面，set拦截器信息)
 * @author HeZeMin
 * @date 2019年7月12日 下午4:27:28
 *
 */
@Aspect
@Component("paramAspect")
public class ParamAspect {
    private static final Log LOG = LogFactory.getLog(ParamAspect.class);
    private static LocalVariableTableParameterNameDiscoverer parameterNameDiscovere = new LocalVariableTableParameterNameDiscoverer();

    @Around(value = "@annotation(com.nanyang.common.core.annotation.BindParam)")
    public Object setParam(ProceedingJoinPoint joinPoint) throws Throwable {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Map<String, Object> map = new HashMap<String, Object>();
        String pin = (String) request.getAttribute("pin");
        if(StringUtils.isNotEmpty(pin)){
        	map.put("pin", pin);
        	map.put("gmtCreatePin", pin);
        	map.put("gmtModifiedPin", pin);
        }
        String ip =(String)request.getAttribute("ip");
        if(StringUtils.isNotEmpty(ip)){
        	map.put("ip", ip);
        }
        String companyCode =(String)request.getAttribute("companyCode");
        if(StringUtils.isNotEmpty(companyCode)){
        	map.put("companyCode", companyCode);
        }
        String employeeNo =(String)request.getAttribute("employeeNo");
        if(StringUtils.isNotEmpty(employeeNo)){
        	map.put("employeeNo", employeeNo);
        }
        String deptCode =(String)request.getAttribute("deptCode");
        if(StringUtils.isNotEmpty(deptCode)){
        	map.put("deptCode", deptCode);
        }
        
        
        
        
        // 获取被调用的方法
        Method method = getMethod(joinPoint);
        // 获取参数实例对象 
        Object[] args = joinPoint.getArgs();
        // 获取方法中定义的参数名称
        String[] parameterNames = parameterNameDiscovere.getParameterNames(method);
        // 获取参数上的注解
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        for (Annotation[] parameterAnnotation : parameterAnnotations) {
            int paramIndex = ArrayUtils.indexOf(parameterAnnotations, parameterAnnotation);
            for (Annotation annotation : parameterAnnotation) {
                if (annotation instanceof BindParam) {
                    if (args[paramIndex].getClass().isPrimitive() || args[paramIndex] instanceof String) {
                        String paramName = parameterNames[paramIndex];
                        if (map.containsKey(paramName)) {
                            args[paramIndex] = map.get(paramName);
                        }
                    } else {
                        changObjectValue(args[paramIndex], map);
                    }
                }
            }
        }
        return joinPoint.proceed(args);
    }

    /**
     * 获取当前执行的方法
     *
     * @param joinPoint
     *            连接点
     * @return 方法
     */
    private Method getMethod(ProceedingJoinPoint joinPoint) {
        // 获取方法签名
        String methodName = joinPoint.getSignature().getName();
        // 获取目标类的所有方法
        Method[] methods = joinPoint.getTarget().getClass().getMethods();
        Method resultMethod = null;
        // 查询当前调用的方法
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                // 找到当前要执行的方法
                resultMethod = method;
                break;
            }
        }
        return resultMethod;
    }

    public  void changObjectValue(Object _obj, Map<String, Object> map) {
        try {
            Class<?> resultClz = _obj.getClass();
            Field[] fieldInfo = resultClz.getDeclaredFields(); // 获取class里的所有字段 父类字段获取不到
            
            Class<?> superClass=resultClz.getSuperclass();
            if(superClass!=null){
            	fieldInfo=(Field[]) ArrayUtils.addAll(fieldInfo,superClass.getDeclaredFields());
            }
            for (Field field : fieldInfo) {
                JsonIgnore jsonAnnotation = field.getAnnotation(JsonIgnore.class);
                if (map.containsKey(field.getName()) && jsonAnnotation != null) {
                    field.setAccessible(true); // 成员变量为private,故必须进行此操
                    field.set(_obj, map.get(field.getName()));
                }
            }
        } catch (SecurityException e) {
            LOG.error(CommonEnum.SYSTEM_EXCEPTION.getMessage(), e);
            throw new ServiceException(CommonEnum.SYSTEM_EXCEPTION.getCode(), CommonEnum.SYSTEM_EXCEPTION.getMessage(), e.getMessage());
        } catch (IllegalArgumentException e) {
        	 LOG.error(CommonEnum.SYSTEM_EXCEPTION.getMessage(), e);
        	throw new ServiceException(CommonEnum.SYSTEM_EXCEPTION.getCode(), CommonEnum.SYSTEM_EXCEPTION.getMessage(), e.getMessage());
        } catch (IllegalAccessException e) {
        	 LOG.error(CommonEnum.SYSTEM_EXCEPTION.getMessage(), e);
        	throw new ServiceException(CommonEnum.SYSTEM_EXCEPTION.getCode(), CommonEnum.SYSTEM_EXCEPTION.getMessage(), e.getMessage());
        }catch (Exception e) {
        	 LOG.error(CommonEnum.SYSTEM_EXCEPTION.getMessage(), e);
         	throw new ServiceException(CommonEnum.SYSTEM_EXCEPTION.getCode(), CommonEnum.SYSTEM_EXCEPTION.getMessage(), e.getMessage());

		}
    }

    private static boolean isPrimitive(Object obj) throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException, SecurityException {
        return ((Class<?>) obj.getClass().getField("TYPE").get(null)).isPrimitive();
    }
}
